//onemax problem-depended class
//$Id: onemax.h 175 2009-09-12 17:34:23Z Oleg.Bulychov $
#pragma once
#ifndef ONEMAX_H
#define ONEMAX_H

#include "src/heo/include/random.h"
#include "src/heo/include/fast_stream.h"
#include "src/heo/include/reflection.h"
#include "src/heo/include/optimization_direction.h"
//__________________________________________________________________________________
struct OneMax_Config
{
    double initial_probability_;

    template<class V>
    void accept(V& v)
    {
        v(VAR_(initial_probability),        0.5);
    }
};
//__________________________________________________________________________________
struct OneMax_Problem
{
    int dimension_;

    explicit OneMax_Problem():
        dimension_(0)
    {}

    template<class I>
    bool read(I& in)
    {
        in >> dimension_;
        return dimension_ > 0;
    }
};
//__________________________________________________________________________________
class OneMax_Solution_GA
{
    DISALLOW_COPY_AND_ASSIGN(OneMax_Solution_GA);
public:
    typedef maximization<> TDirection;
    typedef int            TCostType;
protected:
    bool*        data_;
    size_t       dim_;
    TCostType    fitness_;
    bool         changed_;
public:
    mutable double wheel_sector_;


    explicit OneMax_Solution_GA(): data_(NULL), dim_(0)
    {}

    ~OneMax_Solution_GA()
    {
        delete[] data_;
    }

    void init(OneMax_Problem const& problem, OneMax_Config const& cfg)
    {
        dim_  = problem.dimension_;
        data_ = new bool[dim_];
    }

    void generate_Random(OneMax_Config const& cfg, uniform_random& rnd)
    {
        for (size_t i = 0; i < dim_; ++i)
        {
            bool f = rnd.next_Double() < cfg.initial_probability_;
            data_[i] = f;
        }
        changed_ = true;
    }

    void generate_Trivial()
    {
        for (size_t i = 0; i < dim_; ++i)
        {
            data_[i] = false;
        }
        changed_ = false;
        fitness_ = 0;
    }

    int get_Fitness() const
    {
        ASSERT_(!changed_);
        return fitness_;
    }

    void evaluate(OneMax_Problem const& problem)
    {
        if (!changed_)
            return;
        changed_ = false;
        int f = 0;
        for (size_t i = 0; i < dim_; ++i)
        {
            if (data_[i])
                ++f;
        }
        fitness_ = f;
    }

    void cross(OneMax_Solution_GA& genome, uniform_random& rnd)
    {//:simple one point crossover
        ASSERT_(dim_);
        ASSERT_(dim_ == genome.dim_);
        size_t size = dim_;
        //TODO fix me: if size > UINT_MAX?
        size_t j = rnd.next_UInt(static_cast<unsigned>(size));
        for (size_t i = j; i < size; ++i)
        {
            std::swap(data_[i], genome.data_[i]);
        }
        changed_ = genome.changed_ = true;
    }

    void mutate(double mutationProbability, uniform_random& rnd)
    {
        for (size_t i = 0; i < dim_; ++i)
        {
            if (rnd.next_Double() < mutationProbability)
            {
                data_[i] = !data_[i];
                changed_ = true;
            }
        }
    }

    void assign(OneMax_Solution_GA const& genome)
    {
        ASSERT_(dim_);
        ASSERT_(dim_ == genome.dim_);
        size_t size = dim_;
        for (size_t i = 0; i < size; ++i)
        {
            data_[i] = genome.data_[i];
        }
        changed_ = genome.changed_;
        fitness_ = genome.fitness_;
    }

    void print(std::ostream& os, OneMax_Problem const& problem, OneMax_Config const& cfg)
    {
        os << get_Fitness() << lf;
    }

    bool is_Solved(OneMax_Problem const& problem) const
    {
        return fitness_ == problem.dimension_;
    }

    template<class V>
    void accept(V& v)
    {
        v(fitness_);
        v(changed_);
        v(data_, 0, meta::ptr_size(dim_));
    }
};
//__________________________________________________________________________________

#endif
//EOF!
